﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using SystemDiagramNew.TypeDefinition;
using SystemDiagramNew.Utils;

namespace SystemDiagramNew
{
	public class SystemDiagramAnalyser
	{
		public SystemDiagramAnalyser(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
		}

		public SystemDiagramOption Option { get; set; }

		public IProceeding Proceeding { get; set; }

		public void SetProceeding(string message = "", int step = 1)
		{
			if (this.Proceeding == null)
			{
				return;
			}
			this._progress += step;
			this.Proceeding.Report(this._progress, message);
		}

		public PipingSystemInfo Analyse(string sysName, IEnumerable<Element> elements, SystemDiagramOption option)
		{
			return this.Analyse(sysName, elements, option.Angle, option.ScaleX, option.ScaleY, option.ScaleZ);
		}

		public PipingSystemInfo Analyse(string sysName, IEnumerable<Element> elementSet, double angle, double xScale, double yScale, double zScale)
		{
			this._angle = angle;
			this._scale = new XYZ(xScale, yScale, zScale);
			List<MEPCurve> pipeList = (from elem in elementSet
			where elem is MEPCurve
			select elem).Cast<MEPCurve>().ToList<MEPCurve>();
			List<FamilyInstance> familyInstanceList = (from elem in elementSet
			where elem is FamilyInstance
			select elem).Cast<FamilyInstance>().ToList<FamilyInstance>();
			this.SetProceeding("正在提取系统信息...", 1);
			List<Node> nodeList = this.InitializSystem(pipeList, familyInstanceList);
			PipingSystemInfo pipingSystemInfo = new PipingSystemInfo(sysName, nodeList, ForceType.Pressure);
			if (pipingSystemInfo.IsNull)
			{
				return pipingSystemInfo;
			}
			this.SetProceeding("正在分析生成轴测图数据...", 1);
			this.Adjust(ref pipingSystemInfo);
			return pipingSystemInfo;
		}

		private void Adjust(ref PipingSystemInfo pipingSysInfo)
		{
			this.SetProceeding("", 1);
			this.AdjustNode(ref pipingSysInfo);
			this.SetProceeding("", 1);
			this.TransformToShaftSide(ref pipingSysInfo);
			this.SetProceeding("", 1);
			this.DisposeCoverPipes(ref pipingSysInfo);
		}

		private void AdjustNode(ref PipingSystemInfo pipingSysInfo)
		{
			List<Node> nodeList = pipingSysInfo.NodeList;
			List<Node> list = new List<Node>();
			List<Node> list2 = new List<Node>();
			List<Node> list3 = new List<Node>();
			List<Node> list4 = new List<Node>();
			List<Node> list5 = new List<Node>();
			List<Node> list6 = new List<Node>();
			for (int i = 0; i < nodeList.Count; i++)
			{
				Node node = nodeList[i];
				switch (node.TheNodeType)
				{
				case Node.NodeType.NT_PIPEFITTING:
					list2.Add(node);
					break;
				case Node.NodeType.NT_PIPE_TRANSITION_PIECE:
					list.Add(node);
					break;
				case Node.NodeType.NT_PIPEACCESSORY:
					list3.Add(node);
					break;
				case Node.NodeType.NT_SPRINKLERS:
					list4.Add(node);
					break;
				case Node.NodeType.NT_PLUMBING_FIXTURES:
					list5.Add(node);
					break;
				case Node.NodeType.NT_MECHANICAL_EQUIPMENT:
					list6.Add(node);
					break;
				}
			}
			this.AdjustPipefitting(list2, ref pipingSysInfo);
		}

		private void AdjustTransitionPiece(List<Node> nodeList, ref PipingSystemInfo pipingSysInfo)
		{
			for (int i = 0; i < nodeList.Count; i++)
			{
				Node node = nodeList[i];
				List<PipeInfo> pipeList = node.PipeList;
				if (pipeList.Count == 1)
				{
					Node node2 = this.FindNearNode(node, pipingSysInfo.NodeList);
					if (node2 != null)
					{
						node2.AddPipe(node.PipeList[0]);
						pipingSysInfo.RomoveNode(nodeList[i]);
						nodeList.RemoveAt(i);
						i--;
					}
				}
				else if (pipeList.Count == 0)
				{
					pipingSysInfo.RomoveNode(nodeList[i]);
					this.AdjustAloneTransitionPiece(node, ref pipingSysInfo);
					nodeList.RemoveAt(i);
					i--;
				}
			}
		}

		private void AdjustPipefitting(List<Node> nodeList, ref PipingSystemInfo pipingSysInfo)
		{
			foreach (Node node in nodeList)
			{
				if (node.TheNodeType != Node.NodeType.NT_PIPEFITTING_TRAP_S && node.TheNodeType != Node.NodeType.NT_PIPEFITTING_TRAP_P)
				{
					XYZ position = node.Position;
					List<PipeInfo> pipeList = node.PipeList;
					for (int i = 0; i < pipeList.Count; i++)
					{
						this.SetProceeding("", 1);
						PipeInfo pipeInfo = pipeList[i];
						double val = position.DistanceTo(pipeInfo.CurStartPoint(position));
						double val2 = position.DistanceTo(pipeInfo.CurEndPoint(position));
						if (Geometry.LessThan(val, val2))
						{
							pipeInfo.SetCurStartPoint(position, position);
						}
						else
						{
							pipeInfo.SetCurEndPoint(position, position);
						}
					}
				}
			}
		}

		private void AdjustAloneTransitionPiece(Node node, ref PipingSystemInfo pipingSysInfo)
		{
			FamilyInstance familyInstance = node.Component as FamilyInstance;
			if (familyInstance == null)
			{
				return;
			}
			Options options = this.m_Revit.Application.Application.Create.NewGeometryOptions();
			options.ComputeReferences = true;
			options.View = this.m_Revit.Application.ActiveUIDocument.ActiveView;
			List<GeometryObject> geometryObjectArray = RevitVersionFuncs.GetGeometryObjectArray(familyInstance.get_Geometry(options));
			Line line = null;
			int i = 0;
			while (i < geometryObjectArray.Count)
			{
				GeometryObject geometryObject = geometryObjectArray[i];
				if (geometryObject is GeometryInstance)
				{
					using (List<GeometryObject>.Enumerator enumerator = RevitVersionFuncs.GetGeometryObjectArray((geometryObject as GeometryInstance).GetInstanceGeometry()).GetEnumerator())
					{
						while (enumerator.MoveNext())
						{
							object obj = enumerator.Current;
							if (obj is Line)
							{
								line = (obj as Line);
								break;
							}
						}
						goto IL_D6;
					}
					goto IL_C3;
				}
				goto IL_C3;
				IL_D6:
				i++;
				continue;
				IL_C3:
				if (geometryObject is Line)
				{
					line = (geometryObject as Line);
					break;
				}
				goto IL_D6;
			}
			if (null == line)
			{
				return;
			}
			PipeInfo pipeInfo = new PipeInfo
			{
				Component = node.Component,
				StartPoint = line.GetEndPoint(0),
				EndPoint = line.GetEndPoint(1),
				Diameter = 0,
				StartElevation = 0.0,
				EndElevation = 0.0
			};
			int num = 0;
			Node node2 = this.FindNearNode(pipeInfo.StartPoint, pipingSysInfo.NodeList);
			if (node2 != null)
			{
				if (node2.PipeList.Count > 0)
				{
					num = node2.PipeList[0].Diameter;
				}
				pipeInfo.StartElevation = node2.Position.Z;
				node2.AddPipe(pipeInfo);
			}
			Node node3 = this.FindNearNode(pipeInfo.EndPoint, pipingSysInfo.NodeList);
			if (node3 != null)
			{
				if (node3.PipeList.Count > 0)
				{
					PipeInfo pipeInfo2 = node3.PipeList[0];
					if (Geometry.LessThan((double)num, (double)pipeInfo2.Diameter))
					{
						num = pipeInfo2.Diameter;
					}
				}
				pipeInfo.EndElevation = node3.Position.Z;
				node3.AddPipe(pipeInfo);
			}
			pipeInfo.Diameter = num;
		}

		private Node FindNearNode(Node node, List<Node> nodeList)
		{
			Node result = null;
			double num = double.MaxValue;
			int i = 0;
			int index = -1;
			while (i < nodeList.Count)
			{
				Node node2 = nodeList[i];
				if (!node2.IsEqual(node))
				{
					double num2 = node2.Position.DistanceTo(node.Position);
					if (Geometry.LessThan(num2, num))
					{
						index = i;
						num = num2;
					}
				}
				i++;
			}
			if (Geometry.Lessthan_Or_Equal(num, 500.0.MMtoFeet()))
			{
				result = nodeList[index];
			}
			return result;
		}

		private Node FindNearNodeOld(XYZ pt, List<Node> nodeList)
		{
			Node result = null;
			double num = double.MaxValue;
			int i = 0;
			int index = -1;
			while (i < nodeList.Count)
			{
				double num2 = nodeList[i].Position.DistanceTo(pt);
				if (Geometry.LessThan(num2, num))
				{
					index = i;
					num = num2;
				}
				i++;
			}
			if (Geometry.Lessthan_Or_Equal(num, 500.0.MMtoFeet()))
			{
				result = nodeList[index];
			}
			return result;
		}

		private Node FindNearNode(XYZ pt, List<Node> nodeList)
		{
			IEnumerable<Node> source = from node in nodeList
			let space = node.Position.DistanceTo(pt)
			where Geometry.Lessthan_Or_Equal(space, 500.0.MMtoFeet())
			orderby space
			select node;
			if (source.Any<Node>())
			{
				return source.First<Node>();
			}
			return null;
		}

		private void TransformToShaftSide(ref PipingSystemInfo pipingSysInfo)
		{
			this.SetProceeding("", 1);
			Transform identity = Transform.Identity;
			identity.BasisX = XYZ.BasisX * this._scale.X;
			identity.BasisY = XYZ.BasisY * this._scale.Y;
			identity.BasisZ = XYZ.BasisZ * this._scale.Z;
			Transform transform = RevitVersionFuncs.CreateTranslation(pipingSysInfo.NodeList[0].Position).Multiply(identity);
			pipingSysInfo.Transform(transform);
			pipingSysInfo.TransformShaftSide(this._angle);
		}

		private bool GetTransitionPieceConnectPos(FamilyInstance transitionPiece, ref XYZ ptConnectPos1, ref XYZ ptConnectPos2)
		{
			IEnumerable<Connector> source = transitionPiece.MEPModel.ConnectorManager.Connectors.AsEnumerable();
			if (source.Count<Connector>() != 2)
			{
				return false;
			}
			ptConnectPos1 = source.First<Connector>().Origin;
			ptConnectPos2 = source.ElementAt(1).Origin;
			return true;
		}

		private bool GetPipeInfoFromTransitionPiece(FamilyInstance familyInstance, ref PipeInfo pipeInfo)
		{
			XYZ xyz = null;
			XYZ xyz2 = null;
			if (!this.GetTransitionPieceConnectPos(familyInstance, ref xyz, ref xyz2))
			{
				return false;
			}
			int diameter = 0;
			double z = xyz.Z;
			double z2 = xyz.Z;
			double z3 = xyz2.Z;
			pipeInfo = new PipeInfo
			{
				IsPipe = true,
				Component = familyInstance,
				StartPoint = xyz,
				EndPoint = xyz2,
				Diameter = diameter,
				StartElevation = z2,
				EndElevation = z3
			};
			return true;
		}

		private bool GetOtherConnectPos(FamilyInstance transitionPiece, XYZ ptCurrentConnectPos, ref XYZ ptOtherConnectPos)
		{
			Connector connector = transitionPiece.MEPModel.ConnectorManager.Connectors.AsEnumerable().FirstOrDefault((Connector con) => !con.Origin.IsAlmostEqualTo(ptCurrentConnectPos));
			if (connector == null)
			{
				return false;
			}
			ptCurrentConnectPos = connector.Origin;
			return true;
		}

		private void AddInfoToGraphSystemByConnector(Connector connector, ElementId ownerId, PipeInfo pipeInfo, List<FamilyInstance> familyInstanceList, ref Dictionary<XYZ, Node> the2DGraph)
		{
			XYZ xyz = connector.Origin;
			FamilyInstance familyInstance = null;
			IEnumerator enumerator = connector.AllRefs.GetEnumerator();
			{
				while (enumerator.MoveNext())
				{
					Connector refConnector = (Connector)enumerator.Current;
					if (refConnector.Owner.Id.IntegerValue != ownerId.IntegerValue && familyInstanceList.FindIndex((FamilyInstance s) => s.Id.IntegerValue == refConnector.Owner.Id.IntegerValue) != -1)
					{
						familyInstance = (refConnector.Owner as FamilyInstance);
						break;
					}
				}
			}
			Node.NodeType nodeType = Node.NodeType.NT_NULL;
			Element component = null;
			if (familyInstance != null)
			{
				component = familyInstance;
				nodeType = Node.GetNodeType(familyInstance);
				if (nodeType == Node.NodeType.NT_PIPEFITTING || nodeType == Node.NodeType.NT_PIPEACCESSORY)
				{
					xyz = (familyInstance.Location as LocationPoint).Point;
				}
			}
			if (!the2DGraph.ContainsKey(xyz))
			{
				Node value = new Node(nodeType, component, xyz, new List<PipeInfo>
				{
					pipeInfo
				});
				the2DGraph.Add(xyz, value);
				return;
			}
			the2DGraph[xyz].AddPipe(pipeInfo);
		}

		private void AddInfoToGraphSystemByPipe(MEPCurve pipe, List<FamilyInstance> familyInstanceList, ref Dictionary<XYZ, Node> the2DGraph)
		{
			PipeInfo pipeInfo = PipeInfo.FromCurve(pipe);
			foreach (object obj in pipe.ConnectorManager.Connectors)
			{
				Connector connector = (Connector)obj;
				this.AddInfoToGraphSystemByConnector(connector, pipe.Id, pipeInfo, familyInstanceList, ref the2DGraph);
			}
		}

		private void AddInfoToGraphSystemByFamilyInstance(FamilyInstance familyInstance, List<FamilyInstance> familyInstanceList, ref Dictionary<XYZ, Node> the2DGraph)
		{
			Node.NodeType nodeType = Node.GetNodeType(familyInstance);
			PipeInfo pipeInfo = null;
			if (nodeType == Node.NodeType.NT_PIPE_TRANSITION_PIECE)
			{
				if (!this.GetPipeInfoFromTransitionPiece(familyInstance, ref pipeInfo))
				{
					return;
				}
				IEnumerator enumerator = familyInstance.MEPModel.ConnectorManager.Connectors.GetEnumerator();
				{
					while (enumerator.MoveNext())
					{
						object obj = enumerator.Current;
						Connector connector = (Connector)obj;
						this.AddInfoToGraphSystemByConnector(connector, familyInstance.Id, pipeInfo, familyInstanceList, ref the2DGraph);
					}
					return;
				}
			}
			if (nodeType == Node.NodeType.NT_PIPEFITTING)
			{
				XYZ point = ((LocationPoint)familyInstance.Location).Point;
				if (!the2DGraph.ContainsKey(point))
				{
					List<PipeInfo> pipeList = new List<PipeInfo>();
					Node value = new Node(nodeType, familyInstance, point, pipeList);
					the2DGraph.Add(point, value);
					return;
				}
			}
			else
			{
				foreach (object obj2 in familyInstance.MEPModel.ConnectorManager.Connectors)
				{
					XYZ origin = ((Connector)obj2).Origin;
					if (!the2DGraph.ContainsKey(origin))
					{
						List<PipeInfo> pipeList2 = new List<PipeInfo>();
						Node value2 = new Node(nodeType, familyInstance, origin, pipeList2);
						the2DGraph.Add(origin, value2);
					}
					else
					{
						Node node = the2DGraph[origin];
						the2DGraph.Remove(origin);
						Node value3 = new Node(nodeType, familyInstance, origin, node.PipeList);
						the2DGraph.Add(origin, value3);
					}
				}
			}
		}

		private List<Node> InitializSystem(List<MEPCurve> pipeList, List<FamilyInstance> familyInstanceList)
		{
			Dictionary<XYZ, Node> source = new Dictionary<XYZ, Node>(new XYZComparer());
			foreach (MEPCurve pipe in pipeList)
			{
				this.SetProceeding("", 1);
				this.AddInfoToGraphSystemByPipe(pipe, familyInstanceList, ref source);
			}
			foreach (FamilyInstance familyInstance in familyInstanceList)
			{
				this.SetProceeding("", 1);
				this.AddInfoToGraphSystemByFamilyInstance(familyInstance, familyInstanceList, ref source);
			}
			return (from g in source
			select g.Value).ToList<Node>();
		}

		private void DisposeCoverPipes(ref PipingSystemInfo pipingSysInfo)
		{
			List<PipeInfo> list = pipingSysInfo.PipeInfoList();
			int i = 0;
			while (i < list.Count)
			{
				PipeInfo pipeInfo = list[i];
				XYZ xyz = new XYZ(pipeInfo.StartPoint.X, pipeInfo.StartPoint.Y, 0.0);
				XYZ xyz2 = new XYZ(pipeInfo.EndPoint.X, pipeInfo.EndPoint.Y, 0.0);
				Line line = null;
				try
				{
					line = Line.CreateBound(xyz, xyz2);
				}
				catch (Exception)
				{
					goto IL_271;
				}
				goto IL_77;
				IL_271:
				i++;
				continue;
				IL_77:
				int j = i + 1;
				while (j < list.Count)
				{
					PipeInfo pipeInfo2 = list[j];
					XYZ xyz3 = new XYZ(pipeInfo2.StartPoint.X, pipeInfo2.StartPoint.Y, 0.0);
					XYZ xyz4 = new XYZ(pipeInfo2.EndPoint.X, pipeInfo2.EndPoint.Y, 0.0);
					Line line2 = null;
					try
					{
						line2 = Line.CreateBound(xyz3, xyz4);
					}
					catch (Exception)
					{
						goto IL_25E;
					}
					goto IL_F1;
					IL_25E:
					j++;
					continue;
					IL_F1:
					IntersectionResultArray intersectionResultArray;
                    if ((int)line.Intersect(line2, out intersectionResultArray) != 8)
					{
						goto IL_25E;
					}
					XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
					if (xyzpoint.IsAlmostEqualTo(xyz) || xyzpoint.IsAlmostEqualTo(xyz2) || xyzpoint.IsAlmostEqualTo(xyz3) || xyzpoint.IsAlmostEqualTo(xyz4))
					{
						goto IL_25E;
					}
					double num = xyz.DistanceTo(xyzpoint);
					double num2 = xyz.DistanceTo(xyz2);
					double num3 = pipeInfo.StartPoint.DistanceTo(pipeInfo.EndPoint);
					XYZ xyz5 = (pipeInfo.EndPoint - pipeInfo.StartPoint).Normalize();
					XYZ xyz6 = pipeInfo.StartPoint + xyz5 * num3 * num / num2;
					double num4 = xyz3.DistanceTo(xyzpoint);
					double num5 = xyz3.DistanceTo(xyz4);
					double num6 = pipeInfo2.StartPoint.DistanceTo(pipeInfo2.EndPoint);
					XYZ xyz7 = (pipeInfo2.EndPoint - pipeInfo2.StartPoint).Normalize();
					XYZ xyz8 = pipeInfo2.StartPoint + xyz7 * num6 * num4 / num5;
					if (Geometry.LessThan(xyz6.Z, xyz8.Z))
					{
						list[i].AddSplitePoint(xyzpoint);
						goto IL_25E;
					}
					if (Geometry.LessThan(xyz8.Z, xyz6.Z))
					{
						list[j].AddSplitePoint(xyzpoint);
						goto IL_25E;
					}
					goto IL_25E;
				}
				goto IL_271;
			}
		}

		private readonly ExternalCommandData m_Revit;

		private double _angle = 45.0;

		private int _progress;

		private XYZ _scale = new XYZ(1.0, 1.0, 1.0);

		public List<LinkedDocument> LinkedDocuments = new List<LinkedDocument>();
	}
}
